﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using VisualWip.Core;
using VisualWip.Core.Columns;
using VisualWip.Core.Interfaces;
using VisualWip.Core.Utils;
using VisualWip.PresentationModel.ViewModels;
using VisualWip.Util;
using Application = VisualWip.Core.Application;

namespace VisualWip.PresentationModel
{
    public class MainWindowViewModel : WindowViewModel
    {
        private readonly IColumnBuilder _columnBuilder;
        private readonly IPathSelector _pathSelector;
        private readonly DispatcherTimer _refreshTimer;
        private readonly IZoomManager _zoomManager;
        private ICommand _addImageCommand;
        private ICommand _addRichTextCommand;
        private ICommand _addUriCommand;
        private ICommand _clearCommand;
        private ICommand _newWindowCommand;
        private ICommand _openCommand;
        private ICommand _refreshCommand;
        private DateTime _refreshingAt;
        private ICommand _saveAsCommand;
        private ICommand _saveCommand;
        private TimeSpan _timeToRefresh;
        private ICommand _zoomInCommand;
        private ICommand _zoomOutCommand;
        private ICommand _zoomToCommand;

        public MainWindowViewModel(Application application, IEnumerable<IColumnProviderViewModel> providers,
                                   IWindowManager windowManager, IViewModelFactory viewModelFactory,
                                   IColumnBuilder columnBuilder, IPathSelector pathSelector, IZoomManager zoomManager)
            : base(application, application.MainWindow, windowManager, viewModelFactory, zoomManager)
        {
            RecentSettings = new ObservableCollection<RecentSettingsViewModel>();
            Groups = new ObservableCollection<object>();
            _columnBuilder = columnBuilder;
            _pathSelector = pathSelector;
            _zoomManager = zoomManager;
            _refreshTimer = new DispatcherTimer();
            _refreshTimer.Interval = new TimeSpan(0, 0, 1);
            _refreshTimer.Tick += RefreshTimerTick;
            SetRefreshTimerState();
            SetRecentSettings();
            AddGroups(providers);
        }

        public ObservableCollection<RecentSettingsViewModel> RecentSettings { get; private set; }

        public ObservableCollection<object> Groups { get; private set; }

        public ICommand RefreshCommand
        {
            get
            {
                if (_refreshCommand == null)
                {
                    _refreshCommand = new RelayCommand(param => Refresh());
                }
                return _refreshCommand;
            }
        }


        public ICommand NewWindowCommand
        {
            get
            {
                if (_newWindowCommand == null)
                {
                    _newWindowCommand = new RelayCommand(param => NewWindow(), param => CanNewWindow());
                }
                return _newWindowCommand;
            }
        }

        public ICommand OpenCommand
        {
            get
            {
                if (_openCommand == null)
                {
                    _openCommand = new RelayCommand(param => Open());
                }
                return _openCommand;
            }
        }

        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand(param => Save());
                }
                return _saveCommand;
            }
        }

        public ICommand SaveAsCommand
        {
            get
            {
                if (_saveAsCommand == null)
                {
                    _saveAsCommand = new RelayCommand(param => SaveAs());
                }
                return _saveAsCommand;
            }
        }

        public ICommand ClearCommand
        {
            get
            {
                if (_clearCommand == null)
                {
                    _clearCommand = new RelayCommand(param => Clear());
                }
                return _clearCommand;
            }
        }

        public ICommand ZoomInCommand
        {
            get
            {
                if (_zoomInCommand == null)
                {
                    _zoomInCommand = new RelayCommand(param => _zoomManager.ZoomIn(), param => _zoomManager.CanZoomIn());
                }
                return _zoomInCommand;
            }
        }

        public ICommand ZoomOutCommand
        {
            get
            {
                if (_zoomOutCommand == null)
                {
                    _zoomOutCommand = new RelayCommand(param => _zoomManager.ZoomOut(),
                                                       param => _zoomManager.CanZoomOut());
                }
                return _zoomOutCommand;
            }
        }

        public ICommand ZoomToCommand
        {
            get
            {
                if (_zoomToCommand == null)
                {
                    _zoomToCommand = new RelayCommand(param => _zoomManager.ZoomTo(param),
                                                      param => _zoomManager.CanZoomTo(param));
                }
                return _zoomToCommand;
            }
        }

        public int ZoomLevel
        {
            get { return Application.ZoomLevel; }
        }


        public bool SnapToGrid
        {
            get { return Application.SnapToGrid; }
            set { Application.SnapToGrid = value; }
        }


        public bool IsDesignMode
        {
            get { return Application.IsDesignMode; }
            set { Application.IsDesignMode = value; }
        }


        public bool IsAutoRefreshOn
        {
            get { return Application.IsAutoRefreshOn; }
            set { Application.IsAutoRefreshOn = value; }
        }

        public DateTime Refreshed
        {
            get { return Application.Refreshed; }
        }

        public ICommand AddUriCommand
        {
            get
            {
                if (_addUriCommand == null)
                {
                    _addUriCommand = new RelayCommand(param => AddUri(), param => CanAddUri);
                }
                return _addUriCommand;
            }
        }

        protected bool CanAddUri
        {
            get { return true; }
        }

        public ICommand AddRichTextCommand
        {
            get
            {
                if (_addRichTextCommand == null)
                {
                    _addRichTextCommand = new RelayCommand(param => AddText(), param => CanAddText);
                }
                return _addRichTextCommand;
            }
        }


        protected bool CanAddText
        {
            get { return true; }
        }

        public ICommand AddImageCommand
        {
            get
            {
                if (_addImageCommand == null)
                {
                    _addImageCommand = new RelayCommand(param => AddImage(), param => CanAddImage);
                }
                return _addImageCommand;
            }
        }


        protected bool CanAddImage
        {
            get { return true; }
        }

        public TimeSpan TimeToRefresh
        {
            get { return _timeToRefresh; }
            set
            {
                if (value != _timeToRefresh)
                {
                    _timeToRefresh = value;
                    OnPropertyChanged(this, () => TimeToRefresh);
                }
            }
        }

        public DateTime RefreshingAt
        {
            get { return _refreshingAt; }
            set
            {
                if (value != _refreshingAt)
                {
                    _refreshingAt = value;
                    OnPropertyChanged(this, () => RefreshingAt);
                }
            }
        }

        private void AddGroups(IEnumerable<IColumnProviderViewModel> providers)
        {
            AddGroup("Refresh", this);
            AddGroup("Design", this);
            AddGroup("StandardColumnsGroup", this);

            foreach (IColumnProviderViewModel provider in providers)
            {
                AddGroup(provider.ProviderName, provider);
            }
        }

        private void AddGroup(string resourceKey, object dataContext)
        {
            var providerGroup = System.Windows.Application.Current.FindResource(resourceKey) as FrameworkElement;
            if (providerGroup != null)
            {
                providerGroup.DataContext = dataContext;
                Groups.Add(providerGroup);
            }
            else
            {
                throw new ResourceReferenceKeyNotFoundException(
                    String.Format(
                        "Could not find resource key: {0} when building RibbonGroup",
                        resourceKey), resourceKey);
            }
        }


        private void Open()
        {
            PathSelectorResult selectorResult = _pathSelector.OpenSelector();
            if (selectorResult.IsSelectionMade)
                Application.Open(selectorResult.Path);
        }

        private void Save()
        {
            if (Application.CurrentSettingsPath.HasPath)
                Application.Save(Application.CurrentSettingsPath);
            else
                SaveAs();
        }

        private void SaveAs()
        {
            PathSelectorResult selectorResult = _pathSelector.SaveSelector();
            if (selectorResult.IsSelectionMade)
                Application.Save(selectorResult.Path);
        }

        private void Clear()
        {
            Application.Clear();
        }

        private void AddUri()
        {
            _columnBuilder.Build<UriColumn>();
        }

        private void AddText()
        {
            _columnBuilder.Build<RichTextColumn>();
        }

        private void AddImage()
        {
            _columnBuilder.Build<ImageColumn>();
        }

        private void RefreshTimerTick(object sender, EventArgs e)
        {
            RefreshingAt = Refreshed.Add(Application.RefreshTimeSpan);
            TimeToRefresh = RefreshingAt.Subtract(DateTime.Now);
            if (TimeToRefresh.TotalSeconds <= 0)
                Refresh();
        }

        protected override void ApplicationPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.ApplicationPropertyChanged(sender, e);

            if (e.PropertyName == PropertyHelper.Name(() => Application.IsDesignMode))
            {
                OnPropertyChanged(this, () => IsDesignMode);
                return;
            }

            if (e.PropertyName == PropertyHelper.Name(() => Application.SnapToGrid))
            {
                OnPropertyChanged(this, () => SnapToGrid);
                return;
            }

            if (e.PropertyName == PropertyHelper.Name(() => Application.IsAutoRefreshOn))
            {
                OnPropertyChanged(this, () => IsAutoRefreshOn);
                SetRefreshTimerState();
                return;
            }

            if (e.PropertyName == PropertyHelper.Name(() => Application.RecentSettingsPaths))
            {
                SetRecentSettings();
                return;
            }

            if (e.PropertyName == PropertyHelper.Name(() => Application.Refreshed))
            {
                OnPropertyChanged(this, () => Refreshed);
                return;
            }
        }

        private void SetRecentSettings()
        {
            RecentSettings.Clear();
            foreach (SettingsPath recentSettingsPath in Application.RecentSettingsPaths)
            {
                RecentSettings.Add(ViewModelFactory.CreateViewModel(recentSettingsPath) as RecentSettingsViewModel);
            }
        }

        private void SetRefreshTimerState()
        {
            if (Application.IsAutoRefreshOn && !_refreshTimer.IsEnabled)
            {
                _refreshTimer.Start();
            }
            if (!Application.IsAutoRefreshOn && _refreshTimer.IsEnabled)
            {
                _refreshTimer.Stop();
            }
        }

        private void Refresh()
        {
            Application.Refresh(true);
        }

        private bool CanNewWindow()
        {
            return true;
        }

        private void NewWindow()
        {
            Application.AddWindow();
        }
    }
}